package com.ark.frigate.shell.utils.deploy.module;

import com.ark.frigate.shell.utils.JSchUtils;
import com.ark.frigate.shell.utils.deploy.po.MachinePo;
import com.ark.frigate.shell.utils.dto.ConfigPo;
import com.ark.frigate.shell.utils.dto.ResultDto;
import lombok.extern.slf4j.Slf4j;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;

/**
 * TODO
 *
 * @author zengweilong
 * @date 7/15/21 2:36 PM
 */
@Slf4j
public abstract class DeployComponentCore {


    /**
     * 缓存发布
     *
     * @param list
     * @return
     */
    public int deployProcess(List<MachinePo> list, String bakName, String srcFile, boolean restart) {

        for (int i = 0; i < list.size(); i++) {
            MachinePo v = list.get(i);

            // 文件上传
            int result = uploadFile(srcFile, v);
            if (result != 0) {
                JSchUtils jSch = connection(v);
                jSch.execCommand("rm -rf " + v.getWorkspace() + v.getFileName());
                log.info("文件上传失败..{}", v.getHost());
                jSch.closeSession();
                return -1;
            }
            log.info("上传成功..{}", v.getHost());

            // 文件备份
            result = backupFile(bakName, v);
            if (result != 0) {
                JSchUtils jSch = connection(v);
                jSch.execCommand("rm -rf " + v.getWorkspace() + v.getFileName());
                jSch.execCommand("rm -rf " + v.getWorkspace() + bakName + "_bak.zip");
                log.info("备份失败..{}", v.getHost());
                jSch.closeSession();
                return -1;
            }
            log.info("备份成功..{}", v.getHost());

            // 文件部署
            result = deployFile(v);
            if (result != 0) {
                log.info("部署失败..{}", v.getHost());
                return -1;
            }
            log.info("部署成功..{}", v.getHost());

            if (restart) {
                result = startServer(v);
                if (result != 0) {
                    log.info("启动失败..{}", v.getHost());
                    return -1;
                }

                log.info("启动成功..{}", v.getHost());
            }
        }

        return 0;
    }

    /**
     * 文件上传
     *
     * @param zipPath
     * @param machinePo
     */
    public int uploadFile(String zipPath, MachinePo machinePo) {
        log.info("开始文件上传中...{}", machinePo.getHost());
        JSchUtils jSch = connection(machinePo);
        InputStream is = null;
        try {
            File file = new File(zipPath);
            is = new FileInputStream(file);
            String workspace = machinePo.getWorkspace();
            ResultDto resultDto = jSch.sftpUpload(workspace, machinePo.getFileName(), is);
            log.info("IP=[{}], 上传结果=[{}]", machinePo.getHost(), resultDto);
            return resultDto.getCode();
        } catch (Exception e) {
            log.error("文件上传失败upload.fail", e);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (IOException e) {
                    log.error("文件上传失败upload.fail", e);
                }
            }
            if (jSch != null) {
                jSch.closeSession();
            }
        }
        return -1;
    }

    public int backupFile(String bakName, MachinePo machinePo) {
        log.info("开始备份中...{}", machinePo.getHost());
        JSchUtils jSch = connection(machinePo);
        try {
            String workspace = machinePo.getWorkspace();
            // 源文件运行目录
            String srcFile = workspace + machinePo.getBackPath();
            // 备份目录名称
            String bakFileName = "tmp_" + machinePo.getBackPath();
            // 备份目录全名称
            String bakFullPath = workspace + bakFileName;
            // 备份文件压缩后的名字
            String tarFile = workspace + bakName + "_bak.zip";

            // 将运行目录完全Copy到备份目录
            String command = " cp -r " + srcFile + " " + bakFullPath;
            // 删除不需要备份的logs文件夹
            command += "; find " + bakFullPath + "/ -name *.log | xargs rm -f ";
            command += "; rm -rf " + bakFullPath + "/logs";
            // 进入工作目录，进行压缩备份
            command += "; cd " + workspace + "; zip -r " + tarFile + " " + bakFileName;
            // 删除备份全目录
            command += "; rm -rf " + bakFullPath;

            log.info("IP=[{}], 执行备份命令=[{}]", machinePo.getHost(), command);
            ResultDto resultDto = jSch.execCommand(command);
            log.info("IP=[{}], 执行备份结果=[{}]", machinePo.getHost(), resultDto);
            return resultDto.getCode();
        } catch (Exception e) {
            log.error("文件备份失败backup.fail", e);
        } finally {
            if (jSch != null) {
                jSch.closeSession();
            }
        }
        return -1;
    }

    public int startServer(MachinePo machinePo) {
        log.info("开始启动中...{}", machinePo.getHost());
        JSchUtils jSch = connection(machinePo);
        try {
            String workspace = machinePo.getWorkspace();
            String srcFile = workspace + machinePo.getBackPath();
            String shellCommand = " sh " + srcFile + "/bin/stop.sh;  sh " + srcFile + "/bin/start.sh; exit;";
            log.info("IP=[{}] 启动命令=[{}]", machinePo.getHost(), shellCommand);
            ResultDto resultDto = jSch.executeShell(shellCommand);
            log.info("IP=[{}] 启动结果=[{}]", machinePo.getHost(), resultDto);
            return resultDto.getCode();
        } catch (Exception e) {
            log.error("服务启动失败run.fail", e);
        } finally {
            if (jSch != null) {
                jSch.closeSession();
            }
        }
        return -1;
    }

    /**
     * 部署文件
     * 通过文件cp进行删除覆盖
     *
     * @param machinePo
     * @return
     */
    public abstract int deployFile(MachinePo machinePo);

    /**
     * 文件备份
     *
     * @param machinePo
     * @return
     */
    protected JSchUtils connection(MachinePo machinePo) {
        ConfigPo configPo = ConfigPo.builder()
                .host(machinePo.getHost())
                .username(machinePo.getUsername())
                .password(machinePo.getPassword())
                .port(machinePo.getPort()).build();
        JSchUtils jSch = JSchUtils.builder().configPo(configPo).build();
        boolean result = jSch.connect();
        if (!result) {
            log.error("Connection fail ...");
            jSch.closeSession();
            throw new RuntimeException("Connection fail ..." + machinePo.getHost());
        }
        return jSch;
    }
}
